package ar.com.e2solver;

import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import ar.com.e2solver.conf.PuzzleTheme;
import ar.com.e2solver.exception.BusinessException;
import ar.com.e2solver.solver.Individual;
import ar.com.e2solver.solver.PuzzlePrinter;
import ar.com.e2solver.solver.SolverResult;
import ar.com.e2solver.view.E2SolverView;

public final class Main {
	
	private Main(){}

	public static void main(String args[]) {
		boolean runE2 = true;
		try {
			if (args.length == 1) {
				if(args[0].equals("-informe")){
					runInforme();
				} else if(args[0].equals("-prueba")) {
					runPrueba();
					runE2 = false;
				}
			} else if(args.length == 2) {
				if(args[0].equals("-instancia")){
					runInstancia(args[1]);
					runE2 = false;
				}
			}

			if(runE2){
				runInstancia("e2");
			}

		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}

	/**
	 * Itera sobre la poblacion y las iteraciones y muestra el resultado en
	 * consola con formato csv. Se usa para recolectar datos y mostrar informe.
	 * @throws BusinessException 
	 * 
	 * @throws Exception
	 */
	private static void runInforme() throws BusinessException {
		Map<String, InputStream> themeFiles = getThemesFiles();
		
		for (Entry<String, InputStream> entry : themeFiles.entrySet()) {
			runTheme(entry.getKey(), entry.getValue());
		}
	}
	
	private static void runTheme(String themeName, InputStream file) throws BusinessException{
		PuzzleTheme puzzleTheme;
		FileWriter fr = null;
		PrintWriter pw = null;
		
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
			String path = System.getProperty("user.home") + System.getProperty("file.separator") + sdf.format(new Date());
			fr = new FileWriter( path + "_" + themeName + ".csv");
			pw = new PrintWriter(fr);
			puzzleTheme = new PuzzleTheme(file);
			Individual best = null;
	
			E2Solver solver = new E2Solver(puzzleTheme);
			solver.getSolverConfiguration().setShowLog(Boolean.FALSE);

			String header = buildHeader();
			pw.print(header);
			pw.flush();
			
			for (int i = 0; i < 10; i++) {
				System.out.println(header);
				System.out.println("Nombre: " + themeName + " Iteracion: " + i);
				
				for (int poblacion = 15; poblacion <= 50; poblacion += poblacion) {
					for (int iteraciones = 1000; iteraciones <= 128000; iteraciones += iteraciones) {
						solver.getSolverConfiguration().setIterations(iteraciones);
						solver.getSolverConfiguration().setPopulationNumber(poblacion);
						SolverResult result = solver.run();

						String rowStr = buildResultRow(poblacion, result);
						pw.println(rowStr);
						pw.flush();
						System.out.println(rowStr);
						
						if(best == null || best.getFitnessValue() < result.getBestIndividual().getFitnessValue()){
							best = result.getBestIndividual();
						}
					}
				}
				System.out.println("");
				
			}
			PuzzlePrinter.print(best.getPuzzle(), path + "_" + themeName + ".txt");
			
			
		} catch (IOException e) {
			throw new BusinessException(e.getMessage(), e);
		} finally {
			try {
				if(pw != null){
					pw.close();
				}
				if(fr != null){
					fr.close();
				}
			} catch (IOException e) {}
		}		
	}
	
	private static void runInstancia(String themeName) {
		Map<String, InputStream> themeFiles = getThemesFiles();
		InputStream themeFile = themeFiles.get(themeName);
		if(themeFile == null){
			themeFile = themeFiles.get("e2");
		}
		
		PuzzleTheme puzzleTheme;
		try {
			puzzleTheme = new PuzzleTheme(themeFile);
			new E2SolverView(new E2Solver(puzzleTheme));
		
		} catch (BusinessException e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}

	private static void runPrueba() throws BusinessException {
		PuzzleTheme puzzleTheme;
		
		puzzleTheme = new PuzzleTheme();
		E2Solver solver = new E2Solver(puzzleTheme);

		solver.getSolverConfiguration().setIterations(10000);
		solver.getSolverConfiguration().setPopulationNumber(15);
		solver.run();
	}
	
	private static Map<String, InputStream> getThemesFiles() {
		Map<String, InputStream> themeFiles = new HashMap<String, InputStream>();
		String themeRootPath = getThemePath();
		
		themeFiles.put("6", Main.class.getResourceAsStream(themeRootPath + "pieces_06x06.txt"));
		themeFiles.put("7", Main.class.getResourceAsStream(themeRootPath + "pieces_07x07.txt"));
		themeFiles.put("10", Main.class.getResourceAsStream(themeRootPath + "pieces_10x10.txt"));
		themeFiles.put("12", Main.class.getResourceAsStream(themeRootPath + "pieces_12x12.txt"));
		themeFiles.put("14", Main.class.getResourceAsStream(themeRootPath + "pieces_14x14.txt"));
		themeFiles.put("e2", Main.class.getResourceAsStream(themeRootPath + "e2pieces.txt"));

		return themeFiles;
	}
	
	private static String getThemePath() {
		StringBuffer sb = new StringBuffer();
		sb.append(System.getProperty("file.separator"));
		sb.append("samples");
		sb.append(System.getProperty("file.separator"));
		return sb.toString();
	}

	private static String buildResultRow(int poblacion, SolverResult result) {

		StringBuffer sb = new StringBuffer();
		sb.append(poblacion).append(",");
		sb.append(result.getNumberOfIterations()).append(",");
		sb.append(result.getBestIndividual().getFitnessValue()).append(",");
		sb.append(result.getAlgorithmDuration()).append(",");
		sb.append(MessageFormat.format("{0, number, #.##}", result.getPopulationES())).append(",");
		sb.append(MessageFormat.format("{0, number, #.##}", result.getPopulationVS())).append(",");
		sb.append(result.getMaxPossibleFitness());
		return sb.toString();
	}

	private static String buildHeader() {
		StringBuffer sb = new StringBuffer();
		sb.append("poblacion,");
		sb.append("iteraciones,");
		sb.append("bestIndividual,");
		sb.append("duration,");
		sb.append("ES,");
		sb.append("VS,");
		sb.append("MaxPossible");
		return sb.toString();
	}
}
